Extensions > Integrated Extensions > OPC UA Complex Data Extension > Basic OPC UA Complex Data operations > OPC UA Complex Data writing |
To write a complex data information, prepare a value of the UAGenericObject Class, and call one of the Write methods on the EasyUAClient Class as usual. In the UAGenericObject:
For discussion about creating the generic data, refer to Creating generic data. If the GenericData object you have created has a non-null DataType Property, the generic data will be first validated against this associated data type. For details on the validation process, refer to Generic data validation. The validation is optional, because the presence of the data type in the GenericData object is also optional. If no validation takes place, same errors may be discovered later during the encoding process. The validation has the advantage that it is done upfront, without a need to contact the server at all. It is therefore recommended to use it, if the data type is available somehow (see also "Resolving the data type" in Navigation in the OPC UA data model).
In some cases, you do not have to provide all data that are part of the data type. For example, it may be possible to omit the value for a field that determines a length of sequence in the same structure. For details, see Generic data auto-complete.
The example below first reads a structured value from the server, and then manipulates (changes) its elements. The modified value is then written to the server. In this case, the data type ID (and also the data type) can be taken over from what has been provided by the Read.
// Shows how to write complex data with OPC UA Complex Data plug-in. using System; using OpcLabs.BaseLib.DataTypeModel; using OpcLabs.EasyOpc.UA; using OpcLabs.EasyOpc.UA.ComplexData; using OpcLabs.EasyOpc.UA.OperationModel; namespace UADocExamples.ComplexData._EasyUAClient { class WriteValue { public static void Main1() { // Define which server and node we will work with. UAEndpointDescriptor endpointDescriptor = "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"; // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported) // or "https://opcua.demo-this.com:51212/UA/SampleServer/" UANodeDescriptor nodeDescriptor = "nsu=http://test.org/UA/Data/ ;i=10239"; // [ObjectsFolder]/Data.Static.Scalar.StructureValue // Instantiate the client object. var client = new EasyUAClient(); // Read a node which returns complex data. // We know that this node returns complex data, so we can type cast to UAGenericObject. Console.WriteLine("Reading..."); UAGenericObject genericObject; try { genericObject = (UAGenericObject)client.ReadValue(endpointDescriptor, nodeDescriptor); } catch (UAException uaException) { Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message); return; } // Modify the data read. // This node returns one of the two data types, randomly (this is not common, usually the type is fixed). The // data types are sub-types of one common type which the data type of the node. We therefore use the data type // ID in the returned UAGenericObject to detect which data type has been returned. // For processing the internals of the data, refer to examples for GenericData and DataType classes. // We know how the data is structured, and have hard-coded a logic that modifies certain values inside. It is // also possible to discover the structure of the data type in the program, and write generic clients that can // cope with any kind of complex data. // // Note that the code below is not fully robust - it will throw an exception if the data is not as expected. Console.WriteLine("Modifying..."); Console.WriteLine(genericObject.DataTypeId); if (genericObject.DataTypeId.NodeDescriptor.Match("nsu=http://test.org/UA/Data/ ;i=9440")) // ScalarValueDataType { // Negate the byte in the "ByteValue" field. var structuredData = (StructuredData)genericObject.GenericData; var byteValue = (PrimitiveData)structuredData.FieldData["ByteValue"]; byteValue.Value = (Byte)~((Byte)byteValue.Value); Console.WriteLine(byteValue.Value); } else if (genericObject.DataTypeId.NodeDescriptor.Match("nsu=http://test.org/UA/Data/ ;i=9669")) // ArrayValueDataType { // Negate bytes at indexes 0 and 1 of the array in the "ByteValue" field. var structuredData = (StructuredData)genericObject.GenericData; var byteValue = (SequenceData)structuredData.FieldData["ByteValue"]; var element0 = (PrimitiveData)byteValue.Elements[0]; var element1 = (PrimitiveData)byteValue.Elements[1]; element0.Value = (Byte)~((Byte)element0.Value); element1.Value = (Byte)~((Byte)element1.Value); Console.WriteLine(element0.Value); Console.WriteLine(element1.Value); } // Write the modified complex data back to the node. // The data type ID in the UAGenericObject is borrowed without change from what we have read, so that the server // knows which data type we are writing. The data type ID not necessary if writing precisely the same data type // as the node has (not a subtype). Console.WriteLine("Writing..."); try { client.WriteValue(endpointDescriptor, nodeDescriptor, genericObject); } catch (UAException uaException) { Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message); } } } }
# Shows how to write complex data with OPC UA Complex Data plug-in. # The QuickOPC package is needed. Install it using "pip install opclabs_quickopc". import opclabs_quickopc # Import .NET namespaces. from System import * from OpcLabs.BaseLib.DataTypeModel import * from OpcLabs.EasyOpc.UA import * from OpcLabs.EasyOpc.UA.OperationModel import * endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer') # or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported) # or 'https://opcua.demo-this.com:51212/UA/SampleServer/' # [ObjectsFolder]/Data.Static.Scalar.StructureValue nodeDescriptor = UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=10239') # Instantiate the client object. client = EasyUAClient() # Read a node which returns complex data. # We know that this node returns complex data, so we can type cast to UAGenericObject. try: print('Reading...') genericObject = IEasyUAClientExtension.ReadValue(client, endpointDescriptor, nodeDescriptor) except UAException as uaException: print('*** Failure: ' + uaException.GetBaseException().Message) exit() # Modify the data read. # This node returns one of the two data types, randomly (this is not common, usually the type is fixed). The # data types are sub-types of one common type which the data type of the node. We therefore use the data type # ID in the returned UAGenericObject to detect which data type has been returned. # # For processing the internals of the data, refer to examples for GenericData and DataType classes. # We know how the data is structured, and have hard-coded a logic that modifies certain values inside. It is # also possible to discover the structure of the data type in the program, and write generic clients that can # cope with any kind of complex data. # # Note that the code below is not fully robust - it will throw an exception if the data is not as expected. print ('Modifying...') print(genericObject.DataTypeId) if genericObject.DataTypeId.NodeDescriptor.Match(UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=9440')): # ScalarValueDataType # Negate the byte in the "ByteValue" field. structuredData = genericObject.GenericData byteValue = structuredData.FieldData.get_Item('ByteValue') # PrimitiveData byteValue.Value = (~byteValue.Value) & 0xFF print(byteValue.Value) elif genericObject.DataTypeId.NodeDescriptor.Match(UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=9669')): # ArrayValueDataType # Negate bytes at indexes 0 and 1 of the array in the "ByteValue" field. structuredData = genericObject.GenericData byteValue = structuredData.FieldData.get_Item('ByteValue') # SequenceData element0 = byteValue.Elements.get_Item(0) # PrimitiveData element1 = byteValue.Elements.get_Item(1) # PrimitiveData element0.Value = (~element0.Value) & 0xFF element1.Value = (~element1.Value) & 0xFF print(element0.Value) print(element1.Value) # Write the modified complex data back to the node. # The data type ID in the UAGenericObject is borrowed without change from what we have read, so that the server # knows which data type we are writing. The data type ID not necessary if writing precisely the same data type # as the node has (not a subtype). try: print('Writing...') IEasyUAClientExtension.WriteValue(client, endpointDescriptor, nodeDescriptor, genericObject) except UAException as uaException: print('*** Failure: ' + uaException.GetBaseException().Message) print() print('Finished.')
' Shows how to write complex data with OPC UA Complex Data plug-in. Imports System Imports OpcLabs.BaseLib.DataTypeModel Imports OpcLabs.EasyOpc.UA Imports OpcLabs.EasyOpc.UA.ComplexData Imports OpcLabs.EasyOpc.UA.OperationModel Namespace ComplexData._EasyUAClient Friend Class WriteValue Public Shared Sub Main1() ' Define which server we will work with. Dim endpointDescriptor As UAEndpointDescriptor = "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer" ' or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported) ' or "https://opcua.demo-this.com:51212/UA/SampleServer/" ' Define which node we will work with. Dim nodeDescriptor As UANodeDescriptor = _ "nsu=http://test.org/UA/Data/ ;i=10239" ' [ObjectsFolder]/Data.Static.Scalar.StructureValue ' Instantiate the client object. Dim client = New EasyUAClient ' Read a node which returns complex data. ' We know that this node returns complex data, so we can type cast to UAGenericObject. Console.WriteLine("Reading...") Dim genericObject As UAGenericObject Try genericObject = CType(client.ReadValue(endpointDescriptor, nodeDescriptor), UAGenericObject) Catch uaException As UAException Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message) Exit Sub End Try ' Modify the data read. ' This node returns one of the two data types, randomly (this is not common, usually the type is fixed). The ' data types are sub-types of one common type which the data type of the node. We therefore use the data type ' ID in the returned UAGenericObject to detect which data type has been returned. ' For processing the internals of the data, refer to examples for GenericData and DataType classes. ' We know how the data is structured, and have hard-coded a logic that modifies certain values inside. It is ' also possible to discover the structure of the data type in the program, and write generic clients that can ' cope with any kind of complex data. ' ' Note that the code below is not fully robust - it will throw an exception if the data is not as expected. Console.WriteLine("Modifying...") Console.WriteLine(genericObject.DataTypeId) If genericObject.DataTypeId.NodeDescriptor.Match("nsu=http://test.org/UA/Data/ ;i=9440") Then ' ScalarValueDataType ' Negate the byte in the "ByteValue" field. Dim structuredData = CType(genericObject.GenericData, StructuredData) Dim byteValue = CType(structuredData.FieldData("ByteValue"), PrimitiveData) byteValue.Value = CType(Not CType(byteValue.Value, Byte), Byte) Console.WriteLine(byteValue.Value) ElseIf genericObject.DataTypeId.NodeDescriptor.Match("nsu=http://test.org/UA/Data/ ;i=9669") Then ' ArrayValueDataType ' Negate bytes at indexes 0 and 1 of the array in the "ByteValue" field. Dim structuredData = CType(genericObject.GenericData, StructuredData) Dim byteValue = CType(structuredData.FieldData("ByteValue"), SequenceData) Dim element0 = CType(byteValue.Elements(0), PrimitiveData) Dim element1 = CType(byteValue.Elements(1), PrimitiveData) element0.Value = CType(Not CType(element0.Value, Byte), Byte) element1.Value = CType(Not CType(element1.Value, Byte), Byte) Console.WriteLine(element0.Value) Console.WriteLine(element1.Value) End If ' Write the modified complex data back to the node. ' The data type ID in the UAGenericObject is borrowed without change from what we have read, so that the server ' knows which data type we are writing. The data type ID not necessary if writing precisely the same data type ' as the node has (not a subtype). Console.WriteLine("Writing...") Try client.WriteValue(endpointDescriptor, nodeDescriptor, genericObject) Catch uaException As UAException Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message) Exit Sub End Try End Sub End Class End Namespace
// Shows how to write complex data with OPC UA Complex Data plug-in. class procedure WriteValue.Main; var ArrayValueDataType: _UANodeDescriptor; ByteValue: _PrimitiveData; ByteValue2: _SequenceData; Client: _EasyUAClient; Element0, Element1: _PrimitiveData; EndpointDescriptor: string; GenericObject: _UAGenericObject; NodeDescriptor: string; ScalarValueDataType: _UANodeDescriptor; StructuredData: _StructuredData; begin // Define which server and node we will work with. EndpointDescriptor := //'http://opcua.demo-this.com:51211/UA/SampleServer'; //'https://opcua.demo-this.com:51212/UA/SampleServer/'; 'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer'; NodeDescriptor := 'nsu=http://test.org/UA/Data/ ;i=10239'; // [ObjectsFolder]/Data.Static.Scalar.StructureValue // Instantiate the client object Client := CoEasyUAClient.Create; // Read a node which returns complex data. // We know that this node returns complex data, so we can type cast to UAGenericObject. WriteLn('Reading...'); try GenericObject := _UAGenericObject(IUnknown(Client.ReadValue(EndpointDescriptor, NodeDescriptor))); except on E: EOleException do begin WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message])); Exit; end; end; // Modify the data read. // This node returns one of the two data types, randomly (this is not common, usually the type is fixed). The // data types are sub-types of one common type which the data type of the node. We therefore use the data type // ID in the returned UAGenericObject to detect which data type has been returned. // For processing the internals of the data, refer to examples for GenericData and DataType classes. // We know how the data is structured, and have hard-coded a logic that modifies certain values inside. It is // also possible to discover the structure of the data type in the program, and write generic clients that can // cope with any kind of complex data. // // Note that the code below is not fully robust - it will throw an exception if the data is not as expected. WriteLn('Modifying...'); WriteLn(GenericObject.DataTypeId.ToString); ScalarValueDataType := CoUANodeDescriptor.Create; ScalarValueDataType.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=9440'; // ScalarValueDataType if GenericObject.DataTypeId.NodeDescriptor.Match(ScalarValueDataType) then begin // Negate the byte in the "ByteValue" field. StructuredData := IUnknown(GenericObject.GenericData) as _StructuredData; ByteValue := IUnknown(StructuredData.FieldData['ByteValue']) as _PrimitiveData; ByteValue.Value := Byte(not (Byte(byteValue.Value))); WriteLn(ByteValue.Value); end else begin ArrayValueDataType := CoUANodeDescriptor.Create; ArrayValueDataType.NodeId.ExpandedText := 'nsu=http://test.org/UA/Data/ ;i=9669'; // ArrayValueDataType if GenericObject.DataTypeId.Nodedescriptor.Match(ArrayValueDataType) then begin // Negate bytes at indexes 0 and 1 of the array in the "ByteValue" field. StructuredData := IUnknown(GenericObject.GenericData) as _StructuredData; ByteValue2 := IUnknown(StructuredData.FieldData['ByteValue']) as _SequenceData; Element0 := IUnknown(ByteValue2.Elements[0]) as _PrimitiveData; Element1 := IUnknown(ByteValue2.Elements[1]) as _PrimitiveData; Element0.Value := Byte(not (Byte(element0.Value))); Element1.Value := Byte(not (Byte(element1.Value))); WriteLn(Element0.Value); WriteLn(Element1.Value); end; end; // Write the modified complex data back to the node. // The data type ID in the UAGenericObject is borrowed without change from what we have read, so that the server // knows which data type we are writing. The data type ID not necessary if writing precisely the same data type // as the node has (not a subtype). WriteLn('Writing...'); try Client.WriteValue(EndpointDescriptor, NodeDescriptor, GenericObject); except on E: EOleException do begin WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message])); Exit; end; end; end;
// Shows how to write complex data with OPC UA Complex Data plug-in. // Define which server and node we will work with. $EndpointDescriptor = //"http://opcua.demo-this.com:51211/UA/SampleServer"; //"https://opcua.demo-this.com:51212/UA/SampleServer/"; "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"; $NodeDescriptor = "nsu=http://test.org/UA/Data/ ;i=10239"; // [ObjectsFolder]/Data.Static.Scalar.StructureValue // Instantiate the client object $Client = new COM("OpcLabs.EasyOpc.UA.EasyUAClient"); // Read a node which returns complex data. // We know that this node returns complex data, so we can type cast to UAGenericObject. printf("Reading...\n"); try { $GenericObject = $Client->ReadValue($EndpointDescriptor, $NodeDescriptor); } catch (com_exception $e) { printf("*** Failure: %s\n", $e->getMessage()); Exit(); } // Modify the data read. // This node returns one of the two data types, randomly (this is not common, usually the type is fixed). The // data types are sub-types of one common type which the data type of the node. We therefore use the data type // ID in the returned UAGenericObject to detect which data type has been returned. // For processing the internals of the data, refer to examples for GenericData and DataType classes. // We know how the data is structured, and have hard-coded a logic that modifies certain values inside. It is // also possible to discover the structure of the data type in the program, and write generic clients that can // cope with any kind of complex data. // // Note that the code below is not fully robust - it will throw an exception if the data is not as expected. printf("Modifying...\n"); printf("%s\n", $GenericObject->DataTypeId); $ScalarValueDataType = new COM("OpcLabs.EasyOpc.UA.UANodeDescriptor"); $ScalarValueDataType->NodeId->ExpandedText = "nsu=http://test.org/UA/Data/ ;i=9440"; // ScalarValueDataType if ($GenericObject->DataTypeId->NodeDescriptor->Match($ScalarValueDataType)) { // Negate the byte in the "ByteValue" field. $StructuredData = $GenericObject->GenericData->AsStructuredData(); $ByteValue = $StructuredData->FieldData["ByteValue"]->AsPrimitiveData(); $ByteValue->Value = ~($ByteValue->Value) & 255; printf("%s\n", $ByteValue->Value); } else { $ArrayValueDataType = new COM("OpcLabs.EasyOpc.UA.UANodeDescriptor"); $ArrayValueDataType->NodeId->ExpandedText = "nsu=http://test.org/UA/Data/ ;i=9669"; // ArrayValueDataType if ($GenericObject->DataTypeId->Nodedescriptor->Match($ArrayValueDataType)) { // Negate bytes at indexes 0 and 1 of the array in the "ByteValue" field. $StructuredData = $GenericObject->GenericData->AsStructuredData(); $ByteValue2 = $StructuredData->FieldData["ByteValue"]->AsSequenceData(); $Element0 = $ByteValue2->Elements[0]->AsPrimitiveData(); $Element1 = $ByteValue2->Elements[1]->AsPrimitiveData(); $Element0->Value = ~($Element0->Value) & 255; $Element1->Value = ~($Element1->Value) & 255; printf("%s\n", $Element0->Value); printf("%s\n", $Element1->Value); } } // Write the modified complex data back to the node. // The data type ID in the UAGenericObject is borrowed without change from what we have read, so that the server // knows which data type we are writing. The data type ID not necessary if writing precisely the same data type // as the node has (not a subtype). printf("Writing...\n"); try { $Client->WriteValue($EndpointDescriptor, $NodeDescriptor, $GenericObject); } catch (com_exception $e) { printf("Failure: %s\n", $e->getMessage()); Exit(); }
Copyright © 2004-2023 CODE Consulting and Development, s.r.o., Plzen. All rights reserved. Web page: www.opclabs.com
Send Documentation Feedback. Resources: Knowledge Base. Technical support: Online Forums, FAQ.